"""
pagamiago - free software script to send PayPal payments

Copyright (C) 2018 Alyssa Rosenzweig

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.
"""

import sys
import json
import requests
import urllib.parse
import time
import random

rsession = requests.Session()


class RequestSession:
    def __init__(self, base, logger=None):
        self.base = base
        self.referer = base

        # the logger should ensure it strips sensitive data like passwords before logging
        self.logger = logger

        self.headers = {
            "User-Agent": "Mozilla/5.0 (X11; Linux i686; rv:85.0) Gecko/20100101 Firefox/85.0",
            "X-Requested-With": "XMLHttpRequest"}

        self.meta = None

    def log_request_data(self, data):
        if self.logger is not None:
            self.logger(data)

    def remove_js_headers(self, headers):
        headers = {k: headers[k]
                   for k in headers if not k.upper()[0:2] == "X-"}
        return headers

    def set_referer(self, referer):
        self.referer = referer

    def get_headers(self, plain_headers):
        headers = {
            "Referer": self.base + self.referer,
        }
        headers.update(self.headers)
        if plain_headers:
            headers = self.remove_js_headers(headers)
        return headers

    def send_request(self, url, data, mode='get', plain_headers=False):
        url = self.base + url
        headers = self.get_headers(plain_headers)
        self.log_request_data(data)

        # Gaussian sleep to be polite
        time.sleep(abs(random.gauss(2.0, 2.5)))

        response = None

        if self.meta is not None:
            data["meta"] = self.meta

        if mode == 'get':
            response = rsession.get(url, headers=headers)
        elif mode == 'post':
            response = rsession.post(url, json=data, headers=headers)
        elif mode == 'post_form':
            response = rsession.post(url, data=data, headers=headers)
        else:
            raise ValueError("invalid request mode")

        # throw exceptions for 400 & 500 level status codes
        response.raise_for_status()

        self.headers["x-csrf-jwt"] = response.headers.get("x-csrf-jwt")

        try:
            return response.json()
        except ValueError:
            return response.text
